package roomAlgorithm;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;
import java.util.Random;

import main.Main;
import main.Room;
import message.message;
import clientHandle.HandleFromClient;

public class RoomGame extends Thread implements Runnable{
	
	private Room room;
	
	
	public RoomGame(Room room) {
		this.room = room;
	}
	
	public Room getRoom() {
		return room;
	}
	
	
	//public void gameStart(String roomID, int port, int client_no){
	public void run() {		
			int mark = 0; 
			int client_no = 3;
			ArrayList<String> clientList = new ArrayList<String>();
			
			// Built the Server
					
			Socket[] aSocket = new Socket[client_no];
			ObjectOutputStream[] aObjectOS = new ObjectOutputStream[client_no];
			ObjectInputStream[] aObjectIS = new ObjectInputStream[client_no];
			
			try{
			// Build a server socket
			//ServerSocket serversocket = new ServerSocket(port);
		
			// Mark the creation time
			 Date creationTime = new Date();
			 System.out.println("Room " + room.getRoomID() + " Start ..............."+creationTime);
			 System.out.println("Accepting client connections");
			 
			 
			 // connect with clients
			 for(int i =0;i<client_no;i++){
				 //aSocket[i] = serversocket.accept();
				 aSocket[i] = room.getClientSocketList().get(i);	
				 
				 aObjectOS[i] = room.getClientSocketOutputStreamList().get(i);//new ObjectOutputStream(aSocket[i].getOutputStream());
				
				 aObjectIS[i] = room.getClientSocketInputStreamList().get(i);//new ObjectInputStream(aSocket[i].getInputStream());
				 
				 clientList.add(room.getClientList().get(i));
				 
				 message startMessage = new message();	
				 startMessage.setString("ready");
				 aObjectOS[i].writeObject(startMessage); 
				 startMessage = (message)aObjectIS[i].readObject();
				 if (!startMessage.getString().equalsIgnoreCase("ready")){
					System.out.println("Client "+i+" is NOT READY!"); 
					System.out.println("Client "+i+ " "+startMessage.getString());
					System.exit(0);
				 }
				 else {
					 System.out.println("Client " + i + " is ready");
				 }
				 startMessage.setString(room.getRoomDetailedInfo());
				 aObjectOS[i].writeObject(startMessage); 
				 
				 /*
				 //get and check login message sent from client
				 message loginMessage = new message();
				 loginMessage = (message)aObjectIS[i].readObject();
				 String loginMessageStr = loginMessage.getString();
				 System.out.println("Login message from Client " + i + ": " + loginMessageStr);
        		 if (loginMessageStr.substring(0, 6).equals(roomID)){
        			 clientList.add(loginMessageStr.substring(6));
        			 System.out.println("Connection from Client " + loginMessageStr.substring(6) + " accepted");
        		 }
        		 else{
        			 // reaccept another socket connection
        			 aSocket[i] = null;
    				 aObjectOS[i] = null;
    				 aObjectIS[i] = null;
    				 i--;
        		 }
        		 */
			 }
			 
			 System.out.println("All clients have been connected successfully");
			 System.out.println(room.getRoomDetailedInfo());
			 
			 
			 //Distribute cards to all clients
			 int[] cardsnum = new int[client_no];
			 for(int i=0;i<client_no;i++){
					cardsnum[i]=7;
			 }
			 for(int p=0;p<7;p++){
				 for(int j=0;j<client_no;j++){
					 message sendMessage = new message();					
					 sendMessage.setString(getCard());
					 sendMessage.setcardsNUM(cardsnum);
					 aObjectOS[j].writeObject(sendMessage);  
					 System.out.println("Distribute card "+sendMessage.getString()+" to client:" +j);
				 }
				 
			 }
			 Thread.sleep(1000);
			 System.out.println("Cards has been distributed to users. ");
			 
			 //serversocket.close();
			 
			 // game start
			 // Let client-1 to play his card
			 message initMessage = new message();
			 message clientMessage = new message();
			 message check = new message();
			 String lastCard="";
			 boolean update = false;//decide the last functional card is effective or not
			 int nextClientNo = 0;
			 int currentClientNo = 0;
			 int counter = 1;
			 
	         initMessage.setToken(true);
	         initMessage.setcardsNUM(cardsnum);
	         System.out.println("Start game: Send to Client "+currentClientNo+" : "+ initMessage.getString());
	         aObjectOS[0].writeObject(initMessage);
	         
	         
	         do{
	        		 update = false;
	        		 currentClientNo = nextClientNo;
	        		 System.out.print("receive from client...");
	        		 clientMessage = (message)aObjectIS[currentClientNo].readObject();
	        		 String messageContent = clientMessage.getString().toUpperCase();
	        		 cardsnum=clientMessage.getcardsNUM();
	        		 System.out.println("Client "+clientMessage.getSender() + " : " + messageContent);
	        		 
	        		 // if one client do not play any card, that is, pass
					 if(messageContent.equalsIgnoreCase("pass")){
						 // give cards to the client according to the previous cards played
						for (int i = 0; i < counter; i++){ 
							message sendCard = new message();
							sendCard.setString(getCard());
							sendCard.setcardsNUM(cardsnum);
							System.out.println("Pass!  Send to Client "+currentClientNo+" : "+ sendCard.getString());
							aObjectOS[currentClientNo].writeObject(sendCard);
						}
						// finish the card sending
						message sendCard = new message();
						sendCard.setString("END");
						sendCard.setcardsNUM(cardsnum);
						System.out.println("pass 's END message: Send to Client "+currentClientNo+" : "+ sendCard.getString());
					 	aObjectOS[currentClientNo].writeObject(sendCard);
					 	counter = 1;
						
					 	// get return from the client who passed before
					 	System.out.print("receive from client...");
					 	 check = (message)aObjectIS[currentClientNo].readObject();
					 	 messageContent = check.getString().toUpperCase();
					 	cardsnum=check.getcardsNUM();
					 	System.out.println("Client "+clientMessage.getSender() + " : " + messageContent);
					 	// the client still pass
					 	 if(messageContent.equalsIgnoreCase("pass")){
					 		lastCard = messageContent;
					 		//System.out.println("Pass to next player !");
					 	 }
					 	 else{
					 		 // the client plays a card at the second chance
					 		 lastCard = messageContent;
					 		 update = true;
					 	 }
					 }
					 
					 // the client after the skipped one has to play the card
					 else if (messageContent.equalsIgnoreCase("SKIP")){
						 
						 lastCard = loseEffect(lastCard);
					 }
					 // the client play one card 
					 else {
					 	lastCard = clientMessage.getString();
					 	update = true;
					 }
					 clientMessage.setString(lastCard);
					 
					 //Skip card
					 if(lastCard.charAt(1) == 'S' && update){

			             lastCard = effect(lastCard);
			             clientMessage.setString(lastCard);
			             update = false;
			            } 
					 
					 //Draw Two card
					 if (lastCard.length() == 2 && lastCard.charAt(1) == 'D' && update){
						 if (counter == 1)
							 counter = 2;
						 else counter+=2;
						 
						 lastCard = effect(lastCard);
						 clientMessage.setString(lastCard);
						 update = false;
					 }
					 
					 //Reverse card
					 if(checkCard(lastCard)){
		        			if(mark == 0){
		        				mark = 1;
		        			}
		        			else mark = 0;
		        		}
					 
					 if(mark == 1){
							if(currentClientNo == 0){
								nextClientNo = client_no -1;
							}
							else nextClientNo = currentClientNo-1;
						}
						else nextClientNo = currentClientNo+1;
					 
	        		 if(nextClientNo >= client_no)
		                    nextClientNo = 0;
	        		 
	        		 if(clientMessage.getSize() == 1){
	        			 lastCard = lastCard + " UNO";
	        			 clientMessage.setString(lastCard);
	        		 }
	        		 
	        		 if(clientMessage.getSize() == 0){
	        			 lastCard = lastCard + " I WIN";
	        			 clientMessage.setString(lastCard);
	        			 
	        			 for(int k = 0; k < client_no; k++){  
			                clientMessage.setToken(false);
			                clientMessage.setcardsNUM(cardsnum);
			                System.out.println("Win: Send to Client "+currentClientNo+" : "+ clientMessage.getString());
			                aObjectOS[k].writeObject(clientMessage);   
			                }
			             
	        			 //update users' score
	        			 for (int i = 0; i<client_no; i++){
	        				 boolean isWin = false;
	        				 if(Integer.parseInt(clientMessage.getSender()) == (Integer.parseInt(room.getClientList().get(i))))
	        					 isWin=true;	        				 
	        				 System.out.println("insert: " + Integer.parseInt(room.getClientList().get(i)) + "win: " + isWin);
	        				 if (Main.getDbAPI().updateScore(Integer.parseInt(room.getClientList().get(i)), isWin)){
	        					 System.out.println("Server: user"+room.getClientList().get(i)+"'s score is updated successful");
	        					
	        				 }else{
	        					 System.out.println("Server: user"+room.getClientList().get(i)+"'s score is NOT updated successful!");
	        				 }
	        			 }
	        			 
	        			 Thread.sleep(2000);
	        			 synchronized (HandleFromClient.flag) {  
	        				 HandleFromClient.flag[0] = room.getRoomID()+"finish";
	        				 HandleFromClient.flag.notifyAll();  
	        	          }  
	        			 
			             this.interrupt();
			             //System.exit(0);
			             
	        			 
	        		 }
	        		 
	        		 
	        		 // turn the play opportunity to next client
	        		 for(int k = 0; k < client_no; k++){
		                   if(k != currentClientNo) {
		                	   clientMessage.setcardsNUM(cardsnum);
		                        if(k == nextClientNo)
		                            clientMessage.setToken(true);
		                        else
		                            clientMessage.setToken(false);
		                        System.out.print("One client finished: Send to client " +k+" : " + clientMessage.getString()+" ; "+clientMessage.isPlaying() + " ; [");
		                        if (clientMessage.getcardsNUM()!=null)
		                        for(int i=0; i<clientMessage.getcardsNUM().length; i++){
		   	        			 System.out.print(clientMessage.getcardsNUM()[i]+" ");
		   	        		 	}
		                        else
		                        	System.out.print("null");
		   	        		 	System.out.println("]");
		                        aObjectOS[k].writeObject(clientMessage);
		                    }
		                }
	        	 
	        	 
	         }while(true);
		}
			
		catch(Exception ex){
			 System.out.println("Exception: " + ex);
		}
	}
	
	// the cards pool
	private static String[] cardlist ={"B0","B1","B2","B3","B4","B5","B6","B7","B8","B9","BS", "BD", "BR",
										"B1","B2","B3","B4","B5","B6","B7","B8","B9","BS", "BD", "BR",
										"G0","G1","G2","G3","G4","G5","G6","G7","G8","G9","GS", "GD", "GR",
										"G1","G2","G3","G4","G5","G6","G7","G8","G9","GS", "GD", "GR",
										"R0","R1","R2","R3","R4","R5","R6","R7","R8","R9","RS", "RD", "RR",
										"R1","R2","R3","R4","R5","R6","R7","R8","R9","RS", "RD", "RR",
										"Y0","Y1","Y2","Y3","Y4","Y5","Y6","Y7","Y8","Y9","YS", "YD", "YR",
										"Y1","Y2","Y3","Y4","Y5","Y6","Y7","Y8","Y9","YS", "YD", "YR",
										"HC","HC","HC","HC","HF","HF","HF","HF"};
	//private static String[] cardlistTest ={"BR", "BD", "RR", "RD", "GR", "GD", "YR", "YD"};
	
	// get one card from the cards pool
	public static String getCard(){
			int m;

			Random ram = new Random();
			m = Math.abs(ram.nextInt()%100);
			return cardlist[m];
			//m = Math.abs(ram.nextInt()%8);
			//return cardlistTest[m];
	}
	
	// make one functional card become effect
	public static String effect(String card){
		if (card.length() == 2)
			return card+"Y";
		return card;
	}
	
	// make one functional card lose effect
	public static String loseEffect(String card){
		if (card.length() == 3)
			return card.substring(0, 2);
		else if (card.length() == 7)
			return card.substring(0,2)+ " UNO";
		else
			return card;
	}
	
	// reverse card
	public static boolean checkCard(String card){
		if(card.charAt(1) == 'R'){
			return true;
		}
		else return false;
	}
	
}
